package com.hongkang.utils;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

import android.R.color;
import android.content.Context;

public abstract class CancelableTask implements Runnable {
	
	private static AtomicInteger ExecutorId = new AtomicInteger();
	
	protected int mId;
	/** Synchronization control for CancelableTask */
	private final Sync sync;
	
	protected Context mContext;
	
	public CancelableTask() {
		mId = ExecutorId.getAndAdd(1);
		sync = new Sync();
	}
	
	public CancelableTask(Context context){
		mId = ExecutorId.getAndAdd(1);
		sync = new Sync();
		mContext = context;
	}
	
	public int getTaskId() {
		return mId;
	}

	public boolean isCancelled() {
		return sync.innerIsCancelled();
	}

	public boolean isDone() {
		return sync.innerIsDone();
	}

	public boolean cancel(boolean mayInterruptIfRunning) {
		return sync.innerCancel(mayInterruptIfRunning);
	}
	
	protected void done() { }

	protected abstract void work();

	/**
	 * 
	 * @param t
	 */
	protected void setException(Throwable t) {
		sync.innerSetException(t);
	}
	
	/**
	 * Sets this Future to the result of its computation
	 * unless it has been cancelled.
	 */
	public void run() {
		sync.innerRun();
	}

	/**
	 * Executes the computation without setting its result, and then
	 * resets this Future to initial state, failing to do so if the
	 * computation encounters an exception or is cancelled.	This is
	 * designed for use with tasks that intrinsically execute more
	 * than once.
	 * @return true if successfully run and reset
	 */
	protected boolean runAndReset() {
		return sync.innerRunAndReset();
	}

	/**
	 * Synchronization control for FutureTask. Note that this must be
	 * a non-static inner class in order to invoke the protected
	 * <tt>done</tt> method. For clarity, all inner class support
	 * methods are same as outer, prefixed with "inner".
	 *
	 * Uses AQS sync state to represent run status
	 */
	private final class Sync extends AbstractQueuedSynchronizer {
		private static final long serialVersionUID = -7828117401763700385L;

		/** State value representing that task is ready to run */
		private static final int READY		= 0;
		/** State value representing that task is running */
		private static final int RUNNING	= 1;
		/** State value representing that task ran */
		private static final int RAN		= 2;
		/** State value representing that task was cancelled */
		private static final int CANCELLED	= 4;

//		/** The underlying callable */
//		private final Runnable runnable;
//		/** The result to return from get() */
//		private V result;
//		/** The exception to throw from get() */
//		private Throwable exception;

		/**
		 * The thread running task. When nulled after set/cancel, this
		 * indicates that the results are accessible. Must be
		 * volatile, to ensure visibility upon completion.
		 */
		private volatile Thread runner;

		private boolean ranOrCancelled(int state) {
			return (state & (RAN | CANCELLED)) != 0;
		}

		/**
		 * Implements AQS base acquire to succeed if ran or cancelled
		 */
		protected int tryAcquireShared(int ignore) {
			return innerIsDone() ? 1 : -1;
		}

		/**
		 * Implements AQS base release to always signal after setting
		 * final done status by nulling runner thread.
		 */
		protected boolean tryReleaseShared(int ignore) {
			runner = null;
			return true;
		}

		boolean innerIsCancelled() {
			return getState() == CANCELLED;
		}

		boolean innerIsDone() {
			return ranOrCancelled(getState()) && runner == null;
		}

		void innerSetException(Throwable t) {
			for (;;) {
				int s = getState();
				if (s == RAN)
					return;
				if (s == CANCELLED) {
					// aggressively release to set runner to null,
					// in case we are racing with a cancel request
					// that will try to interrupt runner
					releaseShared(0);
					return;
				}
				if (compareAndSetState(s, RAN)) {
//					exception = t;
					releaseShared(0);
					done();
					return;
				}
			}
		}

		boolean innerCancel(boolean mayInterruptIfRunning) {
			for (;;) {
				int s = getState();
				if (ranOrCancelled(s))
					return false;
				if (compareAndSetState(s, CANCELLED))
					break;
			}
			if (mayInterruptIfRunning) {
				Thread r = runner;
				if (r != null)
					r.interrupt();
			}
			releaseShared(0);
			done();
			return true;
		}

		void innerRun() {
			if (!compareAndSetState(READY, RUNNING))
				return;

			runner = Thread.currentThread();
			if (getState() == RUNNING) { // recheck after setting thread
				try {
					work();
				} catch (Throwable ex) {
					setException(ex);
					return;
				}
			} else {
				releaseShared(0); // cancel
			}
		}

		boolean innerRunAndReset() {
			if (!compareAndSetState(READY, RUNNING))
				return false;
			try {
				runner = Thread.currentThread();
				if (getState() == RUNNING)
					work();
				runner = null;
				return compareAndSetState(RUNNING, READY);
			} catch (Throwable ex) {
				setException(ex);
				return false;
			}
		}
	}
	
//	private Thread runner = null;
//	private boolean cancel = false;
//	
//	protected int mId;
//	
//	public int getTaskId() {
//		return mId;
//	}
//	
//	public void cancel() {
//		cancel = true;
//		if(runner != null)
//			runner.interrupt();
//	}
//
//	@Override
//	public void run() {
//		if(cancel)
//			return;
//		
//		runner = Thread.currentThread();
//		work();
//		runner = null;
//	}
//	
//	public abstract void work();
}
